﻿using System;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Net;
using System.Web;
using System.Xml;
using System.Xml.Linq;

namespace YTPD.Lib
{
  public class NotSignedInException : Exception { }

  public class UriConverter
  {
    private WebClient _webClient;

    public UriConverter(WebClient webClient)
    {
      _webClient = webClient;
    }

    public string FromYoutubePlaylistToGDataPlaylist(string playlistId)
    {
      return string.Format("http://gdata.youtube.com/feeds/api/playlists/{0}", playlistId);
    }

    public string FromYoutubeVideoToGDataVideo(string videoId)
    {
      return string.Format("http://gdata.youtube.com/feeds/api/videos/{0}", videoId);
    }

    public string GetPlaylistId(string playlistUri)
    {
      var newUri = new Uri(playlistUri, UriKind.Absolute);
      var queryVariables = HttpUtility.ParseQueryString(newUri.Query);

      return queryVariables["p"];
    }

    public string GetVideoId(string uri)
    {
      var newUri = new Uri(uri, UriKind.Absolute);
      var queryVariables = HttpUtility.ParseQueryString(newUri.Query);

      return queryVariables["v"];
    }

    public string GetFlvUriFromYoutubeVideoUri(string videoId)
    {
      var viewUri = buildVideoViewUri(videoId);
      var responseString = _webClient.DownloadString(viewUri);
      if (isAuthenticationRequired(responseString))
      {
        throw new NotSignedInException();
      }

      var tId = getTId(responseString);

      var downloadUri = buildVideoDownloadViewUri(videoId, tId);
      return string.IsNullOrEmpty(tId) ? string.Empty : downloadUri;
    }

    private static string buildVideoDownloadViewUri(string videoId, string tId)
    {
      const string DOWNLOAD_URI = "http://youtube.com/get_video?video_id=";
      var downloadUri = DOWNLOAD_URI + videoId + "&t=" + tId;
      return downloadUri;
    }

    private static string buildVideoViewUri(string videoId)
    {
      const string VIEW_URI = "http://www.youtube.com/watch?v=";
      var uri = VIEW_URI + videoId;
      return uri;
    }

    private static bool isAuthenticationRequired(string responseString)
    {
      return new Regex("(?i)Sign in to YouTube").Matches(responseString).Count > 0;
    }

    private static string getTId(string responseString)
    {
      var matchCollection = new Regex("(?<=\"t\":\\s\")([^(\\&|$\")]*)").Matches(responseString);
      var regexMatch = matchCollection.Count > 0 ? matchCollection[0] : null;
      var tId = regexMatch != null && regexMatch.Groups.Count > 1 ?
                  regexMatch.Groups[1].Value :
                  string.Empty;
      return tId;
    }

    public bool IsYoutubeUri(string uri)
    {
      return !string.IsNullOrEmpty(uri) &&
        (IsPlaylistUri(uri) || IsSingleVideoUri(uri));
    }

    public bool IsSingleVideoUri(string videoUri)
    {
      return IsYoutubeTheHostname(videoUri) &&
             !string.IsNullOrEmpty(GetVideoId(videoUri));
    }

    public bool IsPlaylistUri(string playlistUri)
    {
      return IsYoutubeTheHostname(playlistUri) &&
             !string.IsNullOrEmpty(GetPlaylistId(playlistUri));
    }

    public bool IsYoutubeTheHostname(string videoUri)
    {
      bool isVideoUri = false;
      Uri uri;
      isVideoUri = Uri.TryCreate(videoUri, UriKind.Absolute, out uri) &&
                   uri.Host.EndsWith("youtube.com", StringComparison.CurrentCultureIgnoreCase);

      return isVideoUri;
    }
  }
}
